package com.bwie.system.service.impl;

import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSONObject;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.domain.*;
import com.bwie.common.domain.request.AttractionReq;
import com.bwie.common.domain.request.UserReq;
import com.bwie.common.domain.response.AttractionResp;
import com.bwie.common.exception.BizException;
import com.bwie.common.result.PageResult;
import com.bwie.common.utils.JwtUtils;
import com.bwie.system.mapper.AttractionMapper;
import com.bwie.system.mapper.TypeMapper;
import com.bwie.system.mapper.UserGiftMapper;
import com.bwie.system.remote.SystemRemote;
import com.bwie.system.service.AttractionService;
import com.bwie.system.service.TypeService;
import com.bwie.system.service.UserGiftService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.netty.handler.codec.compression.Bzip2Decoder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @className: AttractionServiceImpl
 * @Description: TODO
 * @version: v1.８.0
 * @author:
 * @date:
 */
@Service
public class AttractionServiceImpl implements AttractionService {
    @Autowired
    private AttractionMapper attractionMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private TypeService typeService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SystemRemote systemRemote;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private UserGiftMapper userGiftMapper;
    @Autowired
    private UserGiftService userGiftService;


    @Override
    public PageResult<AttractionResp> attractionList(AttractionReq attractionReq) {
        User login = getLogin(request);

        PageHelper.startPage(attractionReq.getPageNum(),attractionReq.getPageSize());
        List<AttractionResp> list =  attractionMapper.attractionList(attractionReq);

        //根据当前登录人获取预约记录
        UserAttraction userAttraction = new UserAttraction();
        userAttraction.setUserId(login.getId());
        List<UserAttraction> records = attractionMapper.userAttractionList(userAttraction);
        //获取分类数据
        List<Type> types = typeService.typeList();
        //处理分类名称
        list.forEach(attractionResp -> {
            types.forEach(type -> {
                if(attractionResp.getTypeId().equals(type.getId())){
                    attractionResp.setType(type.getType());
                }
            });

            //当联查预约记录表中存在当前登录人预约景点记录时，标记景点预约状态
            attractionResp.setOrderStatus(0);

            records.forEach(userAttraction1 -> {
                if(attractionResp.getId().equals(userAttraction1.getAttractionId())){
                    //设置预约状态
                    attractionResp.setOrderStatus(1);
                }
            });

        });
        //组装分页数据并返回结果
        PageInfo<AttractionResp> pageInfo = new PageInfo<>(list);
        return new PageResult<>(pageInfo.getTotal(), list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUserAttraction(UserAttraction userAttraction) {
        User login = getLogin(request);
        Boolean b = redisTemplate.hasKey("toAdd");
        if(b){
           throw new BizException("请勿重复添加");
        }
        //添加预约记录
        userAttraction.setUserId(login.getId());
        userAttraction.setCreateTime(new Date());
        userAttraction.setStatus(1);
        //使用字符串精度更准确
        BigDecimal multiplicand = new BigDecimal(String.valueOf(userAttraction.getNumber()));
        BigDecimal multiply = userAttraction.getPrice().multiply(multiplicand);
        userAttraction.setTotalPrice(multiply);

        //删除防抖
        redisTemplate.delete("toAdd");
        //添加记录
        attractionMapper.addUserAttraction(userAttraction);
        //扣除金额
        UserReq userReq = new UserReq();
        userReq.setId(login.getId());
        userReq.setBalance(userAttraction.getTotalPrice());
        userReq.setSort("0");
        systemRemote.updBalanceById(userReq);
        //添加兑换记录
        userGiftService.addUserGift(userAttraction.getUserGiftList());
    }

    /**
     * 防抖
     */
    @Override
    public void toAdd() {
        redisTemplate.opsForValue().set("toAdd", 1, 1, TimeUnit.MINUTES);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRecord(UserAttraction userAttraction) throws InterruptedException {

        /**
         * 接口幂等
         */
        Boolean b = redisTemplate.opsForValue().setIfAbsent("toDel", 1,1,TimeUnit.MINUTES);
        if(!b){
            Thread.sleep(2000);
            deleteRecord(userAttraction);
        }
        User login = getLogin(request);
        //若用户已兑换礼品，则禁止执行退票操作
        List<UserGift> byUserId = userGiftMapper.findByUserId(login.getId());
        if(byUserId.size()>0){
            throw new BizException("用户已兑换礼品，无法退票");
        }

        //删除记录(根据UAID删除)
        attractionMapper.deleteRecordById(userAttraction);
        //退款
        UserReq userReq = new UserReq();
        userReq.setId(login.getId());
        userReq.setBalance(userAttraction.getPrice());
        userReq.setSort("1");
        systemRemote.updBalanceById(userReq);

        //mq异步通知
        String msg = "尊敬的"+login.getUsername()+"用户，您好，您购买的门票总金额"+userAttraction.getPrice()+"已退款至账户，请注意查收";
        UserMsg userMsg = new UserMsg();
        userMsg.setUser(login);
        userMsg.setMsg(msg);
        rabbitTemplate.convertAndSend("sendMs", JSONObject.toJSONString(userMsg));

        //删除分布式锁
        redisTemplate.delete("toDel");
    }

    /**
     * 获取登录人信息
     * @param request
     * @return
     */
    public User getLogin(HttpServletRequest request){
        String token = request.getHeader(TokenConstants.TOKEN);
        String userKey = JwtUtils.getUserKey(token);
        return (User) redisTemplate.opsForValue().get(TokenConstants.LOGIN_TOKEN_KEY + userKey);

    }
}
